package fi.iki.juri.units.generator;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import fi.iki.juri.units.generator.XPathCompiler.ExpressionWrapper;

/**
 * Parses the specification file.
 * 
 * @author Juri Pakaste <juri@iki.fi>
 */
public class SpecificationParser {
	private static final String UNIT_ELEMENT = "unit";
	
	private static final String ID_XPATH = "id";
	private static final String ALIAS_XPATH = "alias";
	private static final String DERIVE_XPATH = "derive";
	private static final String FROM_XPATH = "from";
	private static final String TO_XPATH = "to";
	
	private ExpressionWrapper idPath;
	private ExpressionWrapper aliasPath;
	private ExpressionWrapper derivePath;
	private ExpressionWrapper fromPath;
	private ExpressionWrapper toPath;
	
	public SpecificationParser() {
		XPathCompiler compiler = new XPathCompiler();
		idPath = compiler.compile(ID_XPATH);
		aliasPath = compiler.compile(ALIAS_XPATH);
		derivePath = compiler.compile(DERIVE_XPATH);
		fromPath = compiler.compile(FROM_XPATH);
		toPath = compiler.compile(TO_XPATH);
	}
	
	public Collection<ParsedUnit> parse(final InputStream stream) {
		final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		final ArrayList<ParsedUnit> units = new ArrayList<ParsedUnit>();
		try {
			final Document doc = factory.newDocumentBuilder().parse(stream);
			for (final Element unitElement: new IterableNodeList(doc.getElementsByTagName(UNIT_ELEMENT))) {
				final ParsedUnit unit = new ParsedUnit();
				unit.setId(idPath.readString(unitElement));
				unit.addAliases(aliasPath.readCollection(unitElement));
				unit.setDerive(derivePath.readString(unitElement));
				unit.setFromFormula(fromPath.readString(unitElement));
				unit.setToFormula(toPath.readString(unitElement));
				units.add(unit);
			}
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return units;
	}
}
